package com.baijia.services;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.CompareToBuilder;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
/**
 * Base class for mutable, persistable registered services.
 *
 * @author Marvin S. Addison
 * @author Scott Battaglia
 */

/**
 * @title AbstractRegisteredService
 * @desc 注册在passport的业务系统 
 * @author caoliang
 * @date 2015年12月5日
 * @version 1.0
 */
public abstract class AbstractRegisteredService
        implements RegisteredService, Comparable<RegisteredService>, Serializable {

    private static final long serialVersionUID = 7645279151115635245L;

    private int id = -1;

    private List<String> allowedAttributes = new ArrayList<String>();

    private String description;

    protected String serviceId;

    private String name;

    private String theme;

    private boolean allowedToProxy = true;

    private boolean enabled = true;

    private boolean ssoEnabled = true;

    private boolean anonymousAccess = false;

    private boolean ignoreAttributes = false;

    private int evaluationOrder;
    
    /** 能访问的域名 */
    private List<String> allowDomains;
    
    private String loginAddr;
    
    private String loginSuccessAddr;
    
    private Integer banSeconds;

    /**
     * 用户名要被放在response中
     */
    private String usernameAttribute = null;
    
    /** 登录最大重试次数 */
    private Integer loginMaxTimes;
    /** 输错多少次，开始给错误提示 */
    private Integer loginNoticeTimes;
      
    public void setAnonymousAccess(final boolean anonymousAccess) {
        this.anonymousAccess = anonymousAccess;
    }

    @Override
    public List<String> getAllowedAttributes() {
        return this.allowedAttributes;
    }

    @Override
    public int getId() {
        return this.id;
    }

    @Override
    public String getDescription() {
        return this.description;
    }

    @Override
    public String getServiceId() {
        return this.serviceId;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public String getTheme() {
        return this.theme;
    }

    @Override
    public boolean isEnabled() {
        return this.enabled;
    }

    @Override
    public boolean isSsoEnabled() {
        return this.ssoEnabled;
    }

    @Override
    public boolean equals(Object o) {
        if (o == null) { 
            return false; 
        }
        
        if (this == o)  {
            return true;
        }
        
        if (!(o instanceof AbstractRegisteredService)) {
            return false;
        }

        final AbstractRegisteredService that = (AbstractRegisteredService) o;

        return new EqualsBuilder()
                  .append(this.allowedToProxy, that.allowedToProxy)
                  .append(this.anonymousAccess, that.anonymousAccess)
                  .append(this.enabled, that.enabled)
                  .append(this.evaluationOrder, that.evaluationOrder)
                  .append(this.ignoreAttributes, that.ignoreAttributes)
                  .append(this.ssoEnabled, that.ssoEnabled)
                  .append(this.allowedAttributes, that.allowedAttributes)
                  .append(this.description, that.description)
                  .append(this.name, that.name)
                  .append(this.serviceId, that.serviceId)
                  .append(this.theme, that.theme)
                  .append(this.usernameAttribute, that.usernameAttribute)
                  .isEquals();
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder(7, 31)
                  .append(this.allowedAttributes)
                  .append(this.description)
                  .append(this.serviceId)
                  .append(this.name)
                  .append(this.theme)
                  .append(this.enabled)
                  .append(this.ssoEnabled)
                  .append(this.anonymousAccess)
                  .append(this.ignoreAttributes)
                  .append(this.evaluationOrder)
                  .append(this.usernameAttribute)
                  .toHashCode();
    }

    public void setAllowedAttributes(final List<String> allowedAttributes) {
        if (allowedAttributes == null) {
            this.allowedAttributes = new ArrayList<String>();
        } else {
            this.allowedAttributes = allowedAttributes;
        }
    }

    public void setAllowedToProxy(final boolean allowedToProxy) {
        this.allowedToProxy = allowedToProxy;
    }

    public void setDescription(final String description) {
        this.description = description;
    }

    public void setEnabled(final boolean enabled) {
        this.enabled = enabled;
    }

    public abstract void setServiceId(final String id);

    public void setId(final int id) {
        this.id = id;
    }

    public void setName(final String name) {
        this.name = name;
    }

    public void setSsoEnabled(final boolean ssoEnabled) {
        this.ssoEnabled = ssoEnabled;
    }

    public void setTheme(final String theme) {
        this.theme = theme;
    }

    @Override
    public boolean isIgnoreAttributes() {
        return this.ignoreAttributes;
    }

    public void setIgnoreAttributes(final boolean ignoreAttributes) {
        this.ignoreAttributes = ignoreAttributes;
    }

    @Override
    public void setEvaluationOrder(final int evaluationOrder) {
        this.evaluationOrder = evaluationOrder;
    }

    @Override
    public int getEvaluationOrder() {
        return this.evaluationOrder;
    }

    @Override
    public String getUsernameAttribute() {
        return this.usernameAttribute;
    }

    /**
     * Sets the name of the user attribute to use as the username when providing usernames to this registered service.
     * 
     * <p>Note: The username attribute will have no affect on services that are marked for anonymous access.
     * 
     * @param username attribute to release for this service that may be one of the following values: 
     * <ul>
     *  <li>name of the attribute this service prefers to consume as username</li>. 
     *  <li><code>null</code> to enforce default CAS behavior</li>
     * </ul>
     * @see #isAnonymousAccess()
     */
    public void setUsernameAttribute(final String username) {
        if (StringUtils.isBlank(username)) {
          this.usernameAttribute = null;
        } else {
          this.usernameAttribute = username;
        }
    }
    
    @Override
    public Object clone() throws CloneNotSupportedException {
        final AbstractRegisteredService clone = newInstance();
        clone.copyFrom(this);
        return clone;
    }

    /**
     * Copies the properties of the source service into this instance.
     *
     * @param source Source service from which to copy properties.
     */
    public void copyFrom(final RegisteredService source) {
        this.setId(source.getId());
        this.setAllowedAttributes(new ArrayList<String>(source.getAllowedAttributes()));
        this.setDescription(source.getDescription());
        this.setEnabled(source.isEnabled());
        this.setName(source.getName());
        this.setServiceId(source.getServiceId());
        this.setSsoEnabled(source.isSsoEnabled());
        this.setTheme(source.getTheme());
        this.setIgnoreAttributes(source.isIgnoreAttributes());
        this.setEvaluationOrder(source.getEvaluationOrder());
        this.setUsernameAttribute(source.getUsernameAttribute());
        this.setAllowDomains(source.getAllowDomains());
        this.setLoginAddr(source.getLoginAddr());
        this.setLoginSuccessAddr(source.getLoginSuccessAddr());
    }

    @Override
    public int compareTo(final RegisteredService other) {
        return new CompareToBuilder()
                  .append(this.getEvaluationOrder(), other.getEvaluationOrder())
                  .append(this.getName().toLowerCase(), other.getName().toLowerCase())
                  .toComparison();
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }

    protected abstract AbstractRegisteredService newInstance();

    @Override
    public List<String> getAllowDomains() {
    
        return allowDomains;
    }

    public void setAllowDomains(List<String> allowDomains) {
    
        this.allowDomains = allowDomains;
    }
    @Override
    public String getLoginAddr() {
    
        return this.loginAddr;
    }

    public void setLoginAddr(String loginAddr) {
    
        this.loginAddr = loginAddr;
    }
    @Override
    public String getLoginSuccessAddr() {
    
        return this.loginSuccessAddr;
    }

    public void setLoginSuccessAddr(String loginSuccessAddr) {
    
        this.loginSuccessAddr = loginSuccessAddr;
    }

    public Integer getLoginMaxTimes() {
    
        return loginMaxTimes;
    }

    public void setLoginMaxTimes(Integer loginMaxTimes) {
    
        this.loginMaxTimes = loginMaxTimes;
    }

    public Integer getLoginNoticeTimes() {
    
        return loginNoticeTimes;
    }

    public void setLoginNoticeTimes(Integer loginNoticeTimes) {
    
        this.loginNoticeTimes = loginNoticeTimes;
    }

    public Integer getBanSeconds() {
    
        return banSeconds;
    }

    public void setBanSeconds(Integer banSeconds) {
    
        this.banSeconds = banSeconds;
    }
}
